home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-11-04 | 48.3 KB | 1,396 lines |
- Newsgroups: comp.sources.misc
- From: alan@tharr.UUCP (Alan Saunders)
- Subject: v25i023: QBATCH - a queued batch processing system for UNIX, Part04/06
- Message-ID: <1991Nov5.034825.5074@sparky.imd.sterling.com>
- X-Md4-Signature: 500e591bea767e1c667077198f0e0979
- Date: Tue, 5 Nov 1991 03:48:25 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: alan@tharr.UUCP (Alan Saunders)
- Posting-number: Volume 25, Issue 23
- Archive-name: QBATCH/part04
- Environment: UNIX
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 4 (of 6)."
- # Contents: NEWS doc/chap.05 doc/chap.06 man/qc.l src/config.c
- # src/config.h src/jj.c
- # Wrapped by root@vfib_d on Thu Oct 31 15:46:40 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'NEWS' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'NEWS'\"
- else
- echo shar: Extracting \"'NEWS'\" \(6096 characters\)
- sed "s/^X//" >'NEWS' <<'END_OF_FILE'
- X Current release of QBATCH version 2.0 Aug 30 1991
- X
- X The QBATCH system and its related programs were
- X written by Alan D. Saunders and are
- X Copyright (c) Vita Services Ltd. 1990 and
- X Copyright (c) Vita Fibres Ltd. 1991
- X
- X PLEASE read the NOTICE file for details.
- X
- ORIGINS.
- X
- In 1989 we (as a company) were faced with porting all our software from
- a proprietary operating system to UNIX. Most of the applications were
- based on a two layer transaction processing system which made heavy
- use of the system's batching system. Under UNIX, we attempted to use
- the print spooling system to emulate batch queuing with limited
- success. I undertook to write a batch queueing system which included
- the best of the functions of the old system (plus a lot of enhancements)
- before the new UNIX systems went live. The original system was
- implemented in May 1990, the first Sun SPARCstation went live in the
- October. Apart from incremental enhancements, QBATCH has been going
- strong since then (now live on ten systems in the company).
- X
- In May (or June) 1991 I read a posting in alt.sources.wanted from
- someone looking for a batch queueing system. Simultaneously, the
- software house who's tools we used for the conversion, expressed an
- interest. (They were doing further ports for other users of the same
- proprietary kit.) I therefore 'shar'ed it up and distributed it as
- it then stood. (including posting it in alt.sources). As a result of
- this, I have had a great deal of feedback:
- X
- X---------------------- The story continues ----------------:-
- X
- QBATCH has been totally revamped since the last release. This was done
- in the light of difficulties experienced by several people in trying to
- compile and install it on their systems. QBATCH is now far more easily
- configured for the target platform, and some previously hard-wired
- facilities have been made configurable.
- X
- All (I hope) areas where different platforms provide differing support
- have been moved to a new file config.c. Which of each of the various
- options is used is determined by defines in config.h. (file locking,
- signal handling, and process group handling).
- X
- Configuration options for QBATCH itself (the paths for the spool files
- and the queues themselves) are contained in the first few lines of
- qbatch.h.
- X
- Support for systems that can't exec scripts (containing #!/bin/sh for
- example). Now qp reads the first line of the jcl file and execs the
- program stated therein, instead of the file itself.
- X
- The shell under which the batch job is run can be specified when
- submitting the job using the -s<shell> option, thus allowing for
- example 'js -s/usr/local/bin/perl -n <jobname> <queue> <jclfile>'
- Originally, the batch shell used was always the bourne shell.
- X(this is still the default).
- X
- XEnvironment variables can be prevented from being passed to the batch
- job. By default, all environment variables in force when a job is
- submitted are passed through, and form part of the environment of the
- running job. Now, if a .qxenv file exists in the same directory as the
- queues themselves, then any non- blank lines (not starting with '#')
- are taken to contain (one per line) the names of environment variables
- which are NOT to be passed to the batch job.
- X
- X
- A. D. Saunders August 30 1991
- X
- X----------------------------------------------------------------------
- X
- September 18 1991:
- X
- Much work has been carried out resolving porting problems .. current release
- incorporates these changes.
- X
- Thanks to:
- X
- Chris Metzler (metzler@elvis.physics.lsa.umich.edu)
- X(Port to Stardent S5000)
- X
- John Whitley (G.W. Systems ltd., Tring Herts UK.)
- X(Ports to I386 architecture and HP/UX)
- X
- X..ADS.
- X
- September 23 1991:
- X
- A degree of profile timing has been introduced, real (wall clock),
- user and system times taken by queued jobs are now reported in the
- monitor, and a summary report may be requested with the (new) -s option
- of qf. This reports the totals of each time, and the average per job.
- X
- X..ADS
- X
- October 3 1991
- X
- Profile timing extended to include queueing time (time on queue before
- processing).
- X
- Caught a race condition bug (and learnt a bit more about mandatory and
- advisory file locking!!) js was telling qp that a job was available
- before unlocking the queue. qp was receiving the signal but couldn't
- open the queue to get the job.
- X(Thanks to John Whitley for this one)
- X
- Implemented code which should (?) prevent qp being initialised twice
- for the same queue. removed -r (restart) option from qp.
- X
- Implemented code to allow optional queues to have "NONE" as the default
- monitor. In these cases js will now fail if the queue has "NONE" for
- the monitor and the user submitting the job has not specified a
- monitor on the command line, and their MONITOR environment variable
- is not set.
- X
- modified qf to look for the environment variable if default monitor
- is "NONE".
- X
- Modified qc to allow changes to existing queues (priority, monitor etc.)
- X
- Modified js to replace the default shell with the first line in
- X.<queuename>rc (fixed context queues) if it is of the form:
- X#!<pathspec> [options]
- and if the -s option is not used.
- X
- Tarted up documentation, rehashed man pages to account for above changes.
- X
- Released current version as beta release to local sites.
- X
- X..ADS
- X
- X9 October 1991 bug js coredumps for fixed context queues where
- X#QCONTEXT is defined. Discovered a 'feature':-) in Sun's
- implementation re XPG3 (tm). the core dump was at the following:
- X
- i = sscanf (buff, "%s %d %d", rcmd, &jobuid, &jobgid);
- X
- If jobuid and jobgid are defined (per X-OPEN) as uid_t, and gid_t,
- it results in a bus error!
- X
- bug fixed by using a pair of ints for the sscanf, and moving them
- to job[ug]id.
- X
- X16 October 1991 ..
- Added -n option to qf to get the priority or nice value.
- Added -l option to qf to list summary of flags.
- Added qt program to test queue flags.
- added qa script to list queues available to a user.
- Brought man pages up to date.
- X
- X..ADS
- X
- X31 October 1991
- Wrote documentation... This is preliminary, and not formatted.
- My knowledge of [nt]roff is limited to the creation of man pages,
- and my knowledge of [La]TeX is even less.... Any volunteers?
- X
- X..ADS
- END_OF_FILE
- if test 6096 -ne `wc -c <'NEWS'`; then
- echo shar: \"'NEWS'\" unpacked with wrong size!
- fi
- # end of 'NEWS'
- fi
- if test -f 'doc/chap.05' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'doc/chap.05'\"
- else
- echo shar: Extracting \"'doc/chap.05'\" \(6414 characters\)
- sed "s/^X//" >'doc/chap.05' <<'END_OF_FILE'
- X
- X QBATCH a queued batch processing system for UNIX
- X
- X
- X The QBATCH system and its related programs were
- X written by Alan D. Saunders and are
- X Copyright (c) Vita Services Ltd. 1990 and
- X Copyright (c) Vita Fibres Ltd. 1991
- X
- X5. MONITORS.
- X
- X A monitor in QBATCH terms, is a file to which the combined stdout and
- X stderr output of a job is written. In the absence of any other direction,
- X the monitor for a given queue will have a name <queuename>.mon, and reside
- X in the spooling directory (SPOOLPATH) for that queue. (more will be said
- X later on the location of and access to monitors.)
- X
- X When the queue process engine (qp) for a given queue receives a job to be
- X processed, it will open the monitor and write a timestamp in it before the
- X job is forked. After forking, and before executing the job, qp will
- X attach stdout and stderr to the open monitor. When the job is complete
- X (or is killed) and the child process exits, qp will again write a timestamp
- X in the monitor . The profile timing calculated by qp is also written into
- X the monitor before closing it (as well as accumulated in the queue header)
- X viz:
- X
- X ##
- X ## Queue sopt entry 1 (uid = 0 : root) Job: QBATCH test file
- X ## Started Fri Oct 11 11:18:32 1991
- X ##
- X
- X [ here would appear the stdout and stderr of the job ]
- X
- X ##
- X ## Queue sopt entry 1 (uid = 0 : root) Job: QBATCH test file
- X ## stopped Fri Oct 11 11:18:43 1991
- X ## Times:- Queued: 1:54:34.18 Real: 10.53
- X ## User: 0.06 System: 0.28
- X ## (Job exited with status 0)
- X ##
- X
- X The monitor therefore not only serves to record the output of a job, but
- X also to give some indication of it's performance, and resource usage.
- X
- X Normally, queue default monitors will be publicly readable, to allow users
- X to check on the progress of their jobs. This obviously may be changed by
- X the local system administrator, particularly in the case of monitors
- X potentially containing sensitive information. I might suggest however that
- X a program which puts sensitive information to stdout or stderr should be
- X looked at.
- X
- X The monitor for a queue may be accessed using qf to provide the pathspec.
- X qf -q returns the queue default monitor, and
- X qf -m returns the monitor of the currently running job if there is one,
- X otherwise the queue default monitor.
- X so:
- X more `qf -m work`
- X will allow the user to examine the monitor for the job running in the work
- X queue, and
- X tail -f `qf -m work`
- X will allow the user to watch the progress of the currently running job.
- X
- X The default monitor for a queue is defined using qc with the -m option.
- X If this option is not used, the monitor is created as above in the queue
- X spooling directory. The -m option will cause the absolute pathspec of the
- X option value to be used. If this value is a file, that will be used, If it
- X is a directory, then the file <queuename>.mon will be used in that
- X directory.
- X
- X Users submitting jobs to the queue can also use a -m option to js to
- X overrule the default queue monitor. (the rules are the same).
- X
- X If a user submitting a job has a MONITOR environment variable set, then in
- X the absence of a -m option to js, this will be used to determine the monitor
- X for the job.
- X
- X So, the monitor for a job can be determined several ways:
- X 1. Defaulted when the queue was created.
- X 2. Specified when the queue was created or amended.
- X 3. From the environment of the submitting user.
- X 4 Specified to js when the job is submitted.
- X
- X In each case, if the monitor determined is a file, that will be used. If
- X it is a directory, a file <queuename>.mon will be used in that directory.
- X
- X In the above list, if more than one case is available a source later in the
- X list will overrule a source earlier (a monitor sourced by specifying -m to
- X js will always be used even if a MONITOR environment variable is set.)
- X
- X If a default monitor of "NONE" is specified to qc for either a new or
- X existing queue:
- X
- X qc -m NONE <queuename>
- X
- X Then there will be no default monitor. js then expects the user on
- X submitting a job, to provide a pathspec for a monitor, either through
- X the -m option of js, or through an environment variable "MONITOR". It
- X WILL NOT allow the job to be submitted if a monitor is not specified.
- X
- X If you wish to set up an environment where each user or group of users
- X has their own private monitors for each queue they use, then set up in
- X their .cshrc, .login, or .profile, an environment variable pointing to
- X a DIRECTORY in their own filespace. Monitors named for the queues
- X (viz: <queuename>.mon) will be created and used in that directory.
- X
- X WARNING!
- X
- X 1. Such private monitors are ONLY used for queues whose default monitor
- X is NONE.
- X
- X 2. Any profile information stored in the monitors will be split up
- X across several directories, thus making accounting and tuning more
- X difficult.
- X
- X 3. using 'more `qf -m <queuename>`' may give startling results when
- X used for troubleshooting. (The result will depend on the setting
- X of YOUR MONITOR environment variable, and may not have any
- X relationship to the job you wish to check).
- X
- X Monitors, particularly those of active queues can expand, sometimes quite
- X alarmingly. The system administrator does need to keep a check on them.
- X Local rules and conventions may vary depending on the requirements to keep
- X monitors for post-operative analysis, and or accounting, but something
- X should be done to prevent them getting out of hand. One way, (used on our
- X sites) is to 'age' the monitors on a daily basis using cron. A six (or
- X more or less depending on requirement) day cycle is used, and the monitors
- X for each queue are copied to a history directory and numbered
- X <queuename>.mon.1
- X <queuename>.mon.2
- X ...
- X <queuename>.mon.6
- X On a daily basis, the earliest monitor (6 in this case) is removed and the
- X remaining monitors are renamed:
- X 5->6
- X 4->5
- X ...
- X 1->2
- X and the current monitor is copied in as <queuename>.mon.1.
- X The 'live' monitor can then be truncated (cat /dev/null><monitorspec>).
- X This approach at least keeps the problem manageable.
- X
- END_OF_FILE
- if test 6414 -ne `wc -c <'doc/chap.05'`; then
- echo shar: \"'doc/chap.05'\" unpacked with wrong size!
- fi
- # end of 'doc/chap.05'
- fi
- if test -f 'doc/chap.06' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'doc/chap.06'\"
- else
- echo shar: Extracting \"'doc/chap.06'\" \(6248 characters\)
- sed "s/^X//" >'doc/chap.06' <<'END_OF_FILE'
- X QBATCH .. a queued batch processing system for UNIX
- X
- X
- X The QBATCH system and its related programs were
- X written by Alan D. Saunders and are
- X Copyright (c) Vita Services Ltd. 1990 and
- X Copyright (c) Vita Fibres Ltd. 1991
- X
- X6. CONFIGURATION.
- X
- X When to use QBATCH.
- X
- X The strength of QBATCH, or for that matter any queued batch processing
- X system is in it's use of queues. If you have a series of jobs which
- X cannot be processed in parallel, and must be processed in a given order,
- X then a queued batch processing system is ideal. You could write a
- X (probably large) shell script to process the jobs in the right order, but
- X what of jobs that don't always need to be run? Do you change your
- X accounting application run script at period end to add the period end jobs
- X in the right order? Do you have a separate period end script? Or do you
- X simply submit the jobs to a queue in the right order, and only submit
- X those that need to be run this time?
- X
- X QBATCH however is not limited to the application level. There may be
- X several reasons why jobs must not run in parallel. Not least of these is
- X system loading (or should I say overloading?). If you have a large user
- X base, all of whom are at liberty to chuck large jobs into the background,
- X you'd better have an inexhaustible supply of cpu cycles and swap space for
- X them. You can however ease the processing load by having the jobs
- X submitted to one or more background queues. Which will cause more
- X complaints, the odd user who has to wait a bit longer, or every user who
- X has to wait whilst the system slowly dies?
- X
- X How about resource sharing? If you have a 50 Mb scratch partition, and
- X 100 users each want to create a 10 Mb scratch file, someone's going to be
- X disappointed. If however, those 100 jobs were shared over 5 queues, each
- X user's job could quite happily create it's scratch file.
- X
- X In short a queued batch processing system is desirable if:
- X
- X A. There is a need to order a variable sequence of jobs which must not run
- X in parallel.
- X
- X B. There is a need for resource (including cpu and swap) sharing.
- X
- X What do I call the queues?
- X
- X QBATCH places no constraints on the naming of queues that the system
- X itself doesn't place. Ideally the queue name should be meaningful. Only
- X the first four characters of the name are used as a prefix for naming jcl
- X files, and only 63 characters are catered for in the jcl spoolpath. So
- X for all round compatibility, it would be best if the names were around
- X (or at least unique in the first) four characters.
- X
- X Bearing in mind that the priority (or nice value) of the jobs being run in
- X a queue can be specified, on our systems we have the following queues:
- X
- X One for each of the online transaction processing systems e.g.
- X sopt (sales order processing)
- X
- X One for any reports that CAN be produced concurrently with the online
- X system e.g.
- X sopr (sales order processing reports)
- X
- X One general purpose queue where reporting is none critical.
- X work (general purpose shared reporting queue)
- X
- X One additional queue for sop dispatch notes (where with a lorry waiting,
- X the throughput is time critical). This queue is set to a low nice value
- X (high priority):
- X sopq (dispatch note queue)
- X
- X In addition we have three general purpose queues shared by all users and
- X applications, each running jobs at different priorities, and named for the
- X throughput:
- X fast (for small, fast, high priority jobs)
- X slow (for big resource greedy jobs, runs at low priority)
- X norm (anything else)
- X
- X How Many Queues?
- X
- X QBATCH itself places no limit on the number of queues that may be
- X configured.
- X
- X Points to be taken into account are:
- X a. The need to avoid concurrency in applications.
- X b. The capacity of the system.
- X c. The availability of potentially shared resources.
- X d. Timing constraints.
- X
- X a. At worst there will be a need for a queue per application where
- X concurrency is a problem. This may be tempered by timing constraints
- X within the applications, for example if the batch work for one
- X application tends to be in the morning, and for another in the
- X afternoon, then there is probably no reason that they can't share a
- X queue.
- X
- X b & c. As a 'rule of thumb' take the worst case requirement for an
- X available resource (including cpu cycles and memory) and divide this
- X into the total available of the corresponding resource. This will give
- X the number of queues, each running the worst case job that can be
- X supported. This is NOT a hard and fast rule. By tuning the scripts
- X which submit jobs, (and user training) it is possible to tune the system
- X such that quick, non- cpu intensive (conservative rather than greedy)
- X jobs are submitted to the same queue or group of queues. If these are
- X kept in separate queues from resource greedy jobs then the overall
- X number of queues can be increased. In other words, separate jobs
- X requiring different types of resources into different queues, and tune
- X the queue availability to the availability of the resources.
- X
- X In general, there is no way that a systems administrator can ALWAYS get it
- X right first time. Take a reasonable estimate, implement it, and monitor
- X it. Be prepared to make changes as the actual requirements make
- X themselves known. It's probably better in the early stages to have too
- X few queues rather than too many. It's got to be easier to add a queue,
- X and change one or two scripts to use the new queue, than to remove one,
- X and try to remember which scripts used it!
- X
- X If the system is a large multi user system, with a large user base, then
- X perhaps a more systematical approach can be taken. If the users are
- X separated into groups, then access to queues may be restricted to certain
- X groups by using fixed context queues. Once sufficient queues to cater for
- X the major systems jobs have been considered, then other general purpose
- X queues could be configured on a group by group (individual or shared)
- X basis.
- END_OF_FILE
- if test 6248 -ne `wc -c <'doc/chap.06'`; then
- echo shar: \"'doc/chap.06'\" unpacked with wrong size!
- fi
- # end of 'doc/chap.06'
- fi
- if test -f 'man/qc.l' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'man/qc.l'\"
- else
- echo shar: Extracting \"'man/qc.l'\" \(5942 characters\)
- sed "s/^X//" >'man/qc.l' <<'END_OF_FILE'
- X.TH QC 8L "14 May 1991" QC "QUEUED BATCH PROCESSING SYSTEM"
- X.SH COPYRIGHT
- The
- X.B QBATCH
- system and its related programs are Copyright:
- X.br
- X(c) Vita Services Ltd. 1990
- X.br
- X(c) Vita Fibres Ltd. 1991
- X.SH NAME
- X.BI qc
- X\- Queue create. create a batch processing queue, or alter it's default parameters.
- X.SH SYNOPSIS
- X.B qc
- X[
- X.B \- f
- X]
- X[
- X.BI \-m " monitor"
- X]
- X[
- X.BI \-p " priority"
- X]
- X[
- X.BI \-s " spoolpath"
- X]
- X.B qname
- X|[
- X.BI \-v
- X]
- X.SH DESCRIPTION
- A file of name qname will be created in QUEUEPATH (or in the
- directory to which it is a symbolic link). The file will
- contain a queue header record containing the information
- either as specified in the command line, or as the default values. The
- initial queue status flags will be set to allow entries
- to be submitted, and queue idle.
- X.sp
- If the queue already exists, the header contents will be changed to reflect
- the options specified on the command line.
- X.sp
- If the queue is to be a fixed context queue, (-f option)
- X.B js
- X(the job submit program) will also expect to find a file .<qname>rc in the
- qbatch directory. This file is used to set up the environment in which all
- jobs in this queue will run, and controls access to the queue. The contents
- of the rc file are standard (see note) shell jcl, and are added to the beginning
- of jcl written for submitted jobs, except for certain statements as follows:
- X.TP 15
- X.B #QCONTEXT
- Defines the uid and gid under which jobs run in this queue
- will be processed. If this statement is not present, the submitting
- user's uid and gid will be used.
- X.TP
- X.B syntax:
- X#QCONTEXT <uid> <gid>
- X.br
- X.B NOTE:
- A fixed context queue with a QCONTEXT uid of 0 (root) is NOT permitted.
- X('0' in either field results in the original submittors uid (gid) being used).
- X.TP
- X.B #QUSERS
- If this statement is present, it defines a list of submitting user uids permitted
- to submit jobs to this queue.
- X.TP
- X.B syntax:
- X#QUSERS uid [uid ..]
- X.br
- X[#QUSERS uid [uid ..]]
- X.br
- A maximum of 10 uids may be present in a single QUSERS
- statement, but the statement may be repeated if there are to be more.
- X.TP
- X.B #QGROUPS
- If this statement is present, it defines a list of submitting user gids permitted
- to submit jobs to this queue.
- X.TP
- X.B syntax:
- X#QGROUPS gid [gid ..]
- X.br
- X[#QGROUPS gid [gid ..]]
- X.br
- A maximum of 10 gids may be present in a single QGROUPS
- statement, but the statement may be repeated if there are to be more.
- X.sp
- If neither QUSERS nor QGROUPS are present, any user may submit jobs to
- this queue.
- X.TP
- X.B #QGETENV
- Normally, the user environment is ignored in a fixed context queue. This statement
- provides a mechanism for accessing environment variables, and passing them to the job.
- X.TP
- X.B syntax:
- X#QGETENV <envar>
- X.br
- X[#QGETENV <envar>]
- X.br
- X[..]
- X.TP
- example:
- X#QGETENV PRINTER
- X.br
- will ensure that the user's current setting of the PRINTER environment variable
- is available when the job is running.
- X.TP 0
- Note that wherever a queue name is used, to create a monitor
- filename, or as a prefix for the jcl filename, only the
- first four characters are used. It is therefore advisable
- that queue names are restricted to four characters in
- length.
- X.SH IMPORTANT NOTE
- Since the shell under which batch jobs will run is now definable at submit
- time (see js (l)), it should be noted that the jcl in a <qname>rc file should be
- of the correct syntax for the shell in use. This is only a problem where the -s option to
- js is used. The 'default' shell for a fixed context queue may be forced by including
- X(as the FIRST line in the .<queuename>rc file) a line of the form
- X.br
- X#!<shell pathspec>
- X.br
- This will then override /bin/sh as the default shell for this queue.
- Submit time environment variables are passed directly to the running job, so are shell independent.
- X.SH OPTIONS
- X.TP 12
- X.B \-f
- Toggle the fixed context flag for this queue.
- If the queue does not exist (is being created in this operation)
- then the -f option will cause the fixed context flag to be set (Default is not set).
- If the queue already exists, the -f option will toggle the state of the
- fixed context flag.
- X.TP
- X.BI \-m " monitor"
- Specify a default monitor for this queue.
- monitor may be a directory, or a file. If monitor is a directory,
- the file xxxx.mon will be appended where xxxx is the first
- four characters of the queue file name.
- The maximum length of the entered path is 63 characters.
- If the queue does not exist (is being created in this operation)
- and -m is not specified then a monitor xxxx.mon in the
- spooling directory will be used.
- X.sp
- A special case is if the monitor specified is "NONE" (in upper case).
- In this case the user submitting a job to the queue MUST provide a
- monitor specification, either by using the -m option of js, or through
- an environment variable MONITOR.
- X.TP
- X.BI \-p " priority"
- Specify a priority or 'nice value' at which jobs processed
- in this queue will be run. The priority is a value between -20, and 19
- and is the increment by which the nice value of the running qp activity
- is adjusted when the job is executed. Low values increase the scheduling priority
- of the kernel, high values decrease it. (See the man page for nice()).
- If the queue does not exist (is being created in this operation)
- and -p is not specified priority will be 0.
- X.TP
- X.BI \-s " spoolpath"
- Specify an alternate directory in which to create the jcl
- files for jobs processed in this queue.
- The maximum length of the entered path is 63 characters.
- If the queue does not exist (is being created in this operation)
- and -s is not specified, then the default defined as SPOOLPATH
- in qbatch.h will be used.
- X.TP
- X.BI \-v
- Display QBATCH version and copyright information.
- X.SH FILES
- X.ft B
- QUEUEPATH/*
- X.SH "SEE ALSO"
- X.BR qbatch (1L)
- X.BR jj (1L)
- X.BR jk (1L)
- X.BR jm (1L)
- X.BR jn (1L)
- X.BR jr (1L)
- X.BR js (1L)
- X.BR qa (1L)
- X.BR qd (1L)
- X.BR qe (1L)
- X.BR qf (1L)
- X.BR qg (1L)
- X.BR qh (1L)
- X.BR ql (1L)
- X.BR qp (1L)
- X.BR qs (1L)
- X.BR qt (1L)
- X.BR qw (1L)
- X.BR rc.QBATCH (8L)
- X.BR jobdone (8L)
- X.BR queue (5L)
- X.BR qxenv (5L)
- END_OF_FILE
- if test 5942 -ne `wc -c <'man/qc.l'`; then
- echo shar: \"'man/qc.l'\" unpacked with wrong size!
- fi
- # end of 'man/qc.l'
- fi
- if test -f 'src/config.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/config.c'\"
- else
- echo shar: Extracting \"'src/config.c'\" \(6588 characters\)
- sed "s/^X//" >'src/config.c' <<'END_OF_FILE'
- X/************************************************************************/
- X/* */
- X/* config.c source file differences for varying library support. */
- X/* */
- X/* Copyright (c) Vita Services 1990 */
- X/* (c) Vita Fibres 1990 1991 */
- X/* */
- X/************************************************************************/
- X#include <signal.h>
- X#include "config.h"
- X#include "qbatch.h"
- int fpq, had_usersig, lastflags;
- pid_t childid;
- extern char queue[];
- extern char queuename[];
- void q_version()
- X{
- X puts (&QbSID[5]);
- X puts ("");
- X puts (&QbCR1[5]);
- X puts (&QbCR2[5]);
- X puts ("");
- X exit(0);
- X}
- int bad_queue()
- X{
- X if (strcmp (head.q_magic, "qBq") != 0)
- X {
- X fprintf(stderr,"%s is not a valid QBATCH queue\007\n", queuename);
- X return(-1);
- X }
- X return(0);
- X}
- void tell_qp()
- X/* included here simply because this is where signal.h is defined */
- X{
- X if (head.qh_pid) kill (head.qh_pid, SIGUSR1);
- X}
- X
- X#ifdef NOTRUNC
- int ftruncate(fd, size)
- int fd;
- long size;
- X{return(0);}
- X#endif /* NOTRUNC */
- X
- X#ifdef NO_PGP
- void qb_setpgrp()
- X{
- X return;
- X}
- void kill_child_group()
- X{
- X kill (childid, SIGKILL);
- X}
- void toggle_halt_status(newaction)
- int newaction;
- X{
- X kill (childid, (((newaction &qh_halt) == 0) ? SIGCONT : SIGSTOP));
- X}
- X#endif /* NO_PGP */
- X
- X#ifdef SUNOSPGP
- void qb_setpgrp()
- X{
- X setpgrp(0);
- X}
- void kill_child_group()
- X{
- X killpg (childid, SIGKILL);
- X}
- void toggle_halt_status(newaction)
- int newaction;
- X{
- X killpg (childid, (((newaction &qh_halt) == 0) ? SIGCONT : SIGSTOP));
- X}
- X#endif /* SUNOSPGP */
- X
- X#ifdef XPG3PGP
- void qb_setpgrp()
- X{
- X setpgid(0, 0);
- X}
- void kill_child_group()
- X{
- X kill ((childid * -1), SIGKILL);
- X}
- void toggle_halt_status(newaction)
- int newaction;
- X{
- X kill ((childid * -1), (((newaction &qh_halt) == 0) ? SIGCONT : SIGSTOP));
- X}
- X#endif /* XPG3PGP */
- X
- X#ifdef LOCKF
- void q_lock(fd)
- int fd;
- X{
- X lockf (fd, F_LOCK, 0);
- X}
- X
- void q_unlock(fd)
- int fd;
- X{
- X lockf (fd, F_ULOCK, 0);
- X}
- int q_islock(fd)
- int fd;
- X/* check if the file is locked, return 0 if not locked, non 0 if locked */
- X{
- X return (lockf(fd, F_TEST, 0));
- X}
- X#endif /* LOCKF */
- X
- X#ifdef FLOCK
- X#include <sys/file.h>
- void q_lock(fd)
- int fd;
- X{
- X flock (fd, LOCK_EX);
- X}
- void q_unlock(fd)
- int fd;
- X{
- X flock (fd, LOCK_UN);
- X}
- int q_islock(fd)
- int fd;
- X/* check if the file is locked, return 0 if not locked, non 0 if locked */
- X{
- X return (flock(fd, LOCK_EX|LOCK_NB);
- X}
- X#endif /* FLOCK */
- X
- X#ifdef FCNTL
- X#include <fcntl.h>
- struct flock f_lock;
- void q_lock(fd)
- int fd;
- X{
- X f_lock.l_type = F_WRLCK;
- X f_lock.l_whence = SEEK_SET;
- X f_lock.l_start = 0;
- X f_lock.l_len = 0;
- X /* apply wait lock, if it fails (only via signal) try again) */
- X while (fcntl (fd, F_SETLKW, &f_lock) == -1);
- X}
- void q_unlock(fd)
- int fd;
- X{
- X f_lock.l_type = F_UNLCK;
- X fcntl (fd, F_SETLK, f_lock);
- X}
- int q_islock(fd)
- int fd;
- X/* check if the file is locked, return 0 if not locked, non 0 if locked */
- X{
- X f_lock.l_type = F_WRLCK;
- X f_lock.l_whence = SEEK_SET;
- X f_lock.l_start = 0;
- X f_lock.l_len = 0;
- X return (fcntl (fd, F_SETLK, &f_lock));
- X}
- X#endif /* FCNTL */
- void qb_resetterm();
- void qb_term (value)
- int value;
- X{
- X if (fpq > 0)
- X {
- X q_unlock(fpq);
- X close (fpq);
- X fpq = 0;
- X }
- X if (fpq = 0)
- X {
- X fpq = open (queue, O_RDWR);
- X q_lock(fpq);
- X read (fpq, &head, sizeof (head));
- X lseek (fpq, 0, SEEK_SET);
- X write (fpq, &head, sizeof (head));
- X fpq = 0;
- X }
- X qb_resetterm();
- X exit (value);
- X}
- X
- void qb_exit ()
- X/* Interrupt handler for SIGINT to ensure clean closedown */
- X{
- X qb_term (-1);
- X}
- X
- X#ifdef SIGACTION
- X
- void qb_handle (fun, sig)
- HANDLER_TYPE (*fun)();
- int sig;
- X{
- X struct sigaction actsig;
- X sigemptyset(&actsig.sa_mask);
- X actsig.sa_flags = 0;
- X actsig.sa_handler = (HANDLER_TYPE (*)())fun;
- X sigaction(sig, actsig, (struct sigaction *) NULL);
- X}
- X
- X#endif /* SIGACTION */
- X
- X#ifdef SIGSET
- void qb_handle(fun, sig)
- HANDLER_TYPE (*fun)();
- int sig;
- X{
- X sigset(sig, (HANDLER_TYPE (*)())fun);
- X}
- X#endif /* SIGSET */
- X
- X#ifdef SIGNAL /* WARNING ** older SYSV versions of signal reset the signal */
- X /* handler to SIG_DFL when a signal is taken.. if this is */
- X /* the case #define RE_INSTALL */
- void qb_handle(fun, sig)
- HANDLER_TYPE (*fun)();
- int sig;
- X{
- X signal(sig, (HANDLER_TYPE (*)())fun);
- X}
- X#endif /* SIGNAL */
- X
- X#ifdef SIGVEC
- void qb_handle(fun, sig)
- HANDLER_TYPE (*fun)();
- int sig;
- X{
- X struct sigvec actsig;
- X actsig.sv_mask) = 0
- X actsig.sv_flags = 0;
- X actsig.sv_handler = (HANDLER_TYPE (*)())sig;
- X sigvec(sig, actsig, (struct sigvec *) NULL);
- X}
- X#endif /* SIGVEC */
- void qb_resetterm()
- X{
- X qb_handle (SIG_DFL, SIGABRT);
- X qb_handle (SIG_DFL, SIGHUP);
- X qb_handle (SIG_DFL, SIGTRAP);
- X qb_handle (SIG_DFL, SIGILL);
- X qb_handle (SIG_DFL, SIGSEGV);
- X qb_handle (SIG_DFL, SIGTERM);
- X qb_handle (SIG_DFL, SIGQUIT);
- X qb_handle (SIG_DFL, SIGINT);
- X}
- X
- X/* setup terminal handler for untoward exit */
- void qb_setterm()
- X{
- X qb_handle (qb_exit, SIGABRT);
- X qb_handle (qb_exit, SIGHUP);
- X qb_handle (qb_exit, SIGTRAP);
- X qb_handle (qb_exit, SIGILL);
- X qb_handle (qb_exit, SIGSEGV);
- X qb_handle (qb_exit, SIGTERM);
- X qb_handle (qb_exit, SIGQUIT);
- X qb_handle (qb_exit, SIGINT);
- X}
- X
- void qb_setuser(fun)
- void (*fun)();
- X{
- X had_usersig = 0;
- X qb_handle (fun, SIGUSR1);
- X}
- void qb_resetusr()
- X{
- X qb_handle (SIG_DFL, SIGUSR1);
- X}
- X#ifdef WAIT_XPG3
- X#include <sys/wait.h>
- void q_wait(message)
- char message[];
- X{
- X int waitid;
- X WAIT_TYPE wstatus;
- X while (1)
- X {
- X waitid = wait (&wstatus);
- X if (had_usersig)
- X {
- X#ifdef RE_INSTALL
- X setuser();
- X#endif
- X }
- X if (waitid != childid) continue;
- X if (WIFSTOPPED (wstatus) && (lastflags & qh_halt))
- X { /* suspend processing signal ignore it */
- X continue;
- X }
- X if (WIFEXITED (wstatus) /* has it exited */
- X || WIFSIGNALED (wstatus)) /* or been killed */
- X break;
- X }
- X if (WIFEXITED (wstatus))
- X sprintf (message, "Job exited with status %d", WEXITSTATUS (wstatus));
- X if (WIFSIGNALED (wstatus))
- X sprintf (message, "Job killed by signal %d", WTERMSIG (wstatus));
- X}
- X#endif /* WAIT_XPG3 */
- void qb_pause()
- X{
- X#ifdef SIGPAUSE
- X sigpause(0);
- X#else
- X pause();
- X#endif
- X#ifdef RE_INSTALL
- X qb_setuser() /* re-install interrupt handler */
- X#endif /* RE_INSTALL */
- X}
- END_OF_FILE
- if test 6588 -ne `wc -c <'src/config.c'`; then
- echo shar: \"'src/config.c'\" unpacked with wrong size!
- fi
- # end of 'src/config.c'
- fi
- if test -f 'src/config.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/config.h'\"
- else
- echo shar: Extracting \"'src/config.h'\" \(7187 characters\)
- sed "s/^X//" >'src/config.h' <<'END_OF_FILE'
- X/************************************************************************/
- X/* */
- X/* config.h */
- X/* */
- X/* Copyright (c) Vita Services 1990 */
- X/* (c) Vita Fibres 1990 1991 */
- X/* */
- X/************************************************************************/
- X
- X/* This file contains configurable functions depending on the facilities */
- X/* available in your system libraries. Each group of functions should have */
- X/* ONE (and only one) #define set. Those which are the preferred method */
- X/* according to the X-OPEN (tm) programming guides version 3 are marked XPG3 */
- X
- X/* In order to allow you to configure QBATCH for your system, a brief */
- X/* description of the requirements is included in each section. I would */
- X/* rather you didn't go hacking over the individual function code sections in*/
- X/* config.c. If your system cannot be configured using the existing #defines */
- X/* and code, add another #define or two, and the corresponding code sections.*/
- X
- X/*---------------------------------------------------------------------------*/
- X/* Proces group calls (define only one)
- X/* Allow a signal (SIGKILL, SIGHALT, or SIGCONT) sent to a running job, to be
- X/* also sent to any children that job may have forked.
- X
- X/*#define SUNOSPGP*/ /* setpgrp() and killpg() */
- X#define XPG3PGP /* setpgid() and kill() with negative pid XPG3 */
- X
- X/*#define NO_PGP */ /* some poor misbegotten systems don't support process*/
- X /* groups. If this is defined, signals generated by qp*/
- X /* in response to qh, qg, jk etc will only be sent to */
- X /* the job itself. If the job forks children, they */
- X /* will have to be cleaned up manually. */
- X/*---------------------------------------------------------------------------*/
- X/* File locking calls (define only one) */
- X
- X/* Prevent multiple updates and/or reads of the queue file by applying a */
- X/* 'wait' lock. (Activity calling for a lock is blocked until a lock is */
- X/* available. Locks are freed as soon as possible, and freed by a signal */
- X/* handler if the program terminates abnormally) */
- X
- X#define FCNTL /* use fcntl() calls for file locking (XPG3) */
- X
- X/*#define FLOCK*/ /* use flock() calls */
- X
- X/*#define LOCKF*/ /* use lockf() calls */
- X
- X/*---------------------------------------------------------------------------*/
- X/* Pause awaiting signal calls */
- X/* If the handler needs to be re-installed, define RE_INSTALL) */
- X
- X/* When the queue is idle, the queue process engine 'goes to sleep' until */
- X/* a SIGUSR1 is received from a support program. After receiving the signal, */
- X/* the signal handler may have to be re-installed. */
- X
- X/* the actual call used to pause (define SIGPAUSE if sigpause(0) is to be used */
- X/* comment out the definition if the (XPG) pause() call ist to be used */
- X/* #define SIGPAUSE */
- X
- X/* if the signal handler is reset to SIG_DFL when an interrupt has been */
- X/* received, the signal handler will need to be re-installed each time. */
- X/* if this is the case, uncomment the following #define */
- X/*#define RE_INSTALL */
- X
- X/*---------------------------------------------------------------------------*/
- X/* signal handling calls (define one of these) */
- X
- X/* Signal handling functions are used in two ways in QBATCH */
- X/* first, to release any held locks on the queue files in case of abnormal */
- X/* termination, so that other programs are not held in a deadlock */
- X/* and secondly to trigger a (maybe idle) queue process engine into acting */
- X/* on changes of status in a queue. */
- X/* the first of these will only ever be called once (when the program */
- X/* terminates) so does not need to remain installed when it is triggered. */
- X/* the second MUST ALWAYS BE ACTIVE!! If the process engine is idle, the */
- X/* support programs will send a SIGUSR1 to it's pid to wake it up. If the */
- X/* signal handling functions reset the signal handler to SIG_DFL when a */
- X/* signal is trapped, then it MUST BE REINSTALLED!! (#define RE_INSTALL */
- X/* above.) The variable 'had_usersig' is set in the handler so that pause */
- X/* and wait routines can check if the handler needs to be re-installed. */
- X
- X/*#define SIGACTION*/ /* XPG3 */
- X#define SIGSET
- X/*#define SIGVEC */
- X/*#define SIGNAL */
- X/* the type of the handler function can vary from system to system. it is */
- X/* usually either void or int */
- X/*typedef void HANDLER_TYPE;*/
- typedef int HANDLER_TYPE;
- X
- X/*---------------------------------------------------------------------------*/
- X/* wait calls (define one of these) */
- X
- X/* at this time there is only one define for wait calls, it is included here */
- X/* to take advantage of the RE_INSTALL #define. The function q_wait(ptr) will*/
- X/* wait for a child process to die, and will store in *ptr an appropriate */
- X/* message to be written to the queue monitor. If the wait call is */
- X/* interrupted by another signal, it checks had_usersig and RE_INSTALL to */
- X/* determine what other action to take. If the signal indicates that the */
- X/* has stopped rather than exited, the function loops */
- X/* if you have wait functionality that does not return the exit status of a */
- X/* child (?????) then your function should make *ptr NULL */
- X
- X/* the status location of a wait call can vary from system to system, older */
- X/* versions used a 'union wait', newer ones use int (and some systems use an */
- X/* int but have not changed the analysis macros, so they're still trying to */
- X/* analyse a union wait out of an int without casting it first!!) */
- X
- X/*typedef int WAIT_TYPE; */ /* XPG3 */
- typedef union wait WAIT_TYPE;
- X
- X#define WAIT_XPG3 /* XPG3 */
- X
- X/*---------------------------------------------------------------------------*/
- X/* if your system does NOT have the ftruncate or chsize call to adjust the size */
- X/* of an open file, define this */
- X/*#define NOTRUNC */
- X/* in config.c, ftruncate is a dummy (empty) function, which is compiled if NOTRUNC */
- X/* is defined. If you feel you can create the functionality of ftruncate, you are */
- X/* welcome to add code to this function.*/
- X
- X/* if your system has chsize() instead of ftruncate define this */
- X/*#define ftruncate(a,b) (whatever your call is where a is the open fd, and b is the size) */
- X/*---------------------------------------------------------------------------*/
- X/* time calls (define one of these) */
- X
- X/* what we need here is the clock tick of the system. the result of what is */
- X/* defined here is placed into a variable in time.c */
- X
- X#define QCLOCK_TICK sysconf(_SC_CLK_TCK);
- X/*define QCLOCK_TICK CLK_TCK */
- X/*define QCLOCK_TICK gethz();*/
- X
- X/* Some systems don't define pid_t, if not typedef it here */
- X/*typedef int pid_t*/
- X/* and some don't define these */
- X/*typedef short uid_t*/
- X/*typedef short gid_t*/
- X
- X/* if needed , define these */
- X
- X/*#define strchr index */
- X/*#define strrchr rindex */
- END_OF_FILE
- if test 7187 -ne `wc -c <'src/config.h'`; then
- echo shar: \"'src/config.h'\" unpacked with wrong size!
- fi
- # end of 'src/config.h'
- fi
- if test -f 'src/jj.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/jj.c'\"
- else
- echo shar: Extracting \"'src/jj.c'\" \(5752 characters\)
- sed "s/^X//" >'src/jj.c' <<'END_OF_FILE'
- X/************************************************************************/
- X/* */
- X/* jj .. Job jump. move an entry towards the front of the queue. */
- X/* */
- X/* usage: jj [-e <entryno>] qname */
- X/* */
- X/* Copyright (c) Vita Services 1990 */
- X/* (c) Vita Fibres 1990 1991 */
- X/* */
- X/************************************************************************/
- X
- X#include "qbatch.h"
- int fpq = 0;
- int i, l;
- int killed = 0;
- long j, k;
- int aflag = 0, kflag = 0;
- pid_t jpid = 0;
- uid_t userid = 0, entryno = 0;
- off_t *entries;
- uid_t *uids;
- char queue[128];
- char *queuename;
- char buff [128];
- struct queue_entry entry1;
- X#include "config.h"
- X
- main (argc, argv)
- int argc;
- char *argv[];
- X{
- X int c;
- X extern char *optarg;
- X extern int optind;
- X if (argc == 1)
- X {
- X puts ("Usage: jj -e <entryno> qname");
- X qb_term (0);
- X }
- X while ((c = getopt (argc, argv, "e:v")) != -1)
- X switch (c)
- X {
- X case 'e': entryno = atoi(optarg);
- X break;
- X case 'v': q_version();
- X case '?': qb_term (-1);
- X }
- X if (optind >= argc)
- X {
- X fprintf (stderr, "Missing queue name\n");
- X qb_term (-1);
- X }
- X if (entryno == 0)
- X {
- X fprintf (stderr, "-e (entry number) required for jump\n");
- X qb_exit (-1);
- X }
- X
- X queuename = argv[optind];
- X strcpy (queue, QUEUEPATH);
- X strcat (queue, queuename);
- X qb_setterm();
- X fpq = open (queue, O_RDWR);
- X if (fpq == -1)
- X {
- X fprintf (stderr, "Invalid queue name: %s\n", queuename);
- X qb_term (-1);
- X }
- X q_lock(fpq);
- X read (fpq, &head, sizeof(head));
- X if (bad_queue()) qb_exit(-1);
- X if (head.qh_noentries == 0)
- X {
- X fprintf (stderr, " Queue %s is empty!\n", queuename);
- X qb_term (-1);
- X }
- X userid = getuid();
- X if ((head.qh_flags&qh_halt) == 0)
- X {
- X head.qh_flags += qh_halt;
- X lseek (fpq, 0, SEEK_SET);
- X write (fpq, &head, sizeof(head));
- X q_unlock(fpq);
- X close (fpq);fpq = 0;
- X tell_qp();
- X }
- X do
- X {
- X fpq = open (queue, O_RDWR);
- X q_lock(fpq);
- X read (fpq, &head, sizeof(head));
- X read (fpq, &entry, sizeof(entry));
- X jpid = entry.qe_status;
- X if (jpid != 0) /* something running */
- X {
- X q_unlock(fpq); /* and is the right job! */
- X close (fpq);fpq = 0;
- X fpq = open (queue, O_RDWR);
- X q_lock(fpq);
- X read (fpq, &head, sizeof(head));
- X if (head.qh_noentries == 0)
- X {
- X fprintf (stderr, " Queue %s is empty!\n", queuename);
- X qb_term (-1);
- X }
- X read (fpq, &entry, sizeof(entry));
- X if ((entry.qe_status != jpid) && (jpid != 0)) /* job has changed */
- X {
- X jpid = 0; /* don't kill */
- X }
- X }
- X }
- X while (jpid != entry.qe_status) ;
- X /* the current job is halted */
- X entries = (off_t *) calloc ((head.qh_noentries+1), sizeof(off_t));
- X uids = (uid_t *) calloc ((head.qh_noentries+1), sizeof(off_t));
- X lseek (fpq, sizeof(head), SEEK_SET);
- X l = 0;
- X for (i = 0; i < head.qh_noentries; i++)
- X {
- X j = lseek (fpq, 0L, SEEK_CUR);
- X read (fpq, &entry, sizeof(entry));
- X if (entry.qe_jobno == entryno)
- X {
- X l = i;
- X if ((userid != 0) && (userid != entry.qe_uid))
- X {
- X fprintf (stderr, "Can't jump another's job\n");
- X qb_exit (-1);
- X }
- X }
- X entries[i] = j;
- X uids [i] = entry.qe_uid;
- X }
- X if (l == 0)
- X {
- X fprintf (stderr, "Queue %s entry %d not found\n",queuename, entryno);
- X qb_term (-1);
- X }
- X /* we now have a table (entries) containing the offsets of those wanted */
- X lseek (fpq, entries[l], SEEK_SET);
- X read (fpq, &entry1, sizeof(entry1)); /* get jumped record */
- X for (i=l; i > 1; i--)
- X {
- X if ((userid == 0) || (userid == uids [i-1]))
- X {/* we can jump it */
- X lseek (fpq, entries[i-1], SEEK_SET);
- X read (fpq, &entry, sizeof(entry));
- X write(fpq, &entry, sizeof(entry));
- X }
- X else
- X {
- X lseek (fpq, entries[i], SEEK_SET);
- X write (fpq, &entry1, sizeof(entry1));
- X break;
- X }
- X }
- X if (i == 1)
- X {
- X if ((jpid == 0) && ((userid == 0) || (userid == uids [i-1])))
- X {/* we can jump it */
- X lseek (fpq, entries[i-1], SEEK_SET);
- X read (fpq, &entry, sizeof(entry));
- X write(fpq, &entry, sizeof(entry));
- X lseek (fpq, entries[i-1], SEEK_SET);
- X write(fpq, &entry1, sizeof(entry1));
- X i--;
- X }
- X else
- X {
- X lseek (fpq, entries[i], SEEK_SET);
- X write (fpq, &entry1, sizeof(entry1));
- X }
- X }
- X if (i == l)
- X {
- X fprintf (stderr, "Queue %s can't jump entry no %d\n", queuename, entryno);
- X qb_exit (0);
- X }
- X k = lseek (fpq, sizeof(head), SEEK_SET);
- X
- X lseek (fpq, 0, SEEK_SET);
- X if ((head.qh_flags & qh_halt) != 0)
- X {
- X head.qh_flags -= qh_halt;
- X }
- X
- X write (fpq, &head, sizeof(head));
- X
- X
- X/* right, now either kill or continue first entry (if running) */
- X q_unlock(fpq);
- X close (fpq);fpq = 0;
- X tell_qp();
- X exit (0);
- X}
- END_OF_FILE
- if test 5752 -ne `wc -c <'src/jj.c'`; then
- echo shar: \"'src/jj.c'\" unpacked with wrong size!
- fi
- # end of 'src/jj.c'
- fi
- echo shar: End of archive 4 \(of 6\).
- cp /dev/null ark4isdone
- MISSING=""
- for I in 1 2 3 4 5 6 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 6 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-